{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "508da77e",
   "metadata": {},
   "source": [
    "# 版本依赖说明\n",
    "\n",
    " lanchain >= 0.0.292\n",
    " <br>\n",
    " qianfan >= 0.0.3\n",
    "<br>\n",
    " python >= 3.7\n",
    "\n",
    "\n",
    "\n",
    "# 问答\n",
    "\n",
    "## 用例\n",
    "此处展示了如何使用 Langchian + 千帆 SDK 完成对特定文档完成获取、切分、转为向量并存储，而后根据你的提问来从文中获取答案。\n",
    "并且借助 Langsmith 将整个过程可视化展现\n",
    "\n",
    "## 概览\n",
    "把一个非结构化的文档转成问答链涉及以下步骤：\n",
    "1. `Loading`: 首先我们需要加载数据，非结构化的数据可以从多种渠道加载。点击 [LangChain integration hub](https://integrations.langchain.com/) 查看所有 Langchain 支持的 Loader。\n",
    "每个 Loader 都会返回 Langchian 中的 [`Document`](/docs/components/schema/document) 对象。\n",
    "\n",
    "2. `Splitting`: [文本切分器](/docs/modules/data_connection/document_transformers/) 把 `Documents` 切分成特定的大小。\n",
    "\n",
    "3. `Storage`: `Storage` （例如 [vectorstore](/docs/modules/data_connection/vectorstores/)）会将切分的数据储存起来，通常还附带对文本做 [embedding](https://www.pinecone.io/learn/vector-embeddings/) 。\n",
    "\n",
    "4. `Retrieval`: 用于从 `Storage` 中获取切分的数据，用于后面生成答案。\n",
    "\n",
    "5. `Generation`: 使用提示词和获取到的数据，搭配 [LLM](/docs/modules/model_io/models/llms/) 来生成回答。\n",
    "\n",
    "6. `Conversation` (扩展): 添加 [Memory](/docs/modules/memory/) 模块来在你的问答链上实现多轮对话。\n",
    "\n",
    "![flow.jpeg](img/qa_flow.jpeg)\n",
    "\n",
    "接下来我们会演示如何一步步构造我们自己的流水线，并且实现我们自己定制化的功能\n",
    "\n",
    "## Step 0. Prepare\n",
    "\n",
    "为了能够运行我们的 Demo，首先我们需要下载依赖并且设置环境变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d64b5820",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "langchain                     0.0.292\n",
      "qianfan                       0.0.3\n"
     ]
    }
   ],
   "source": [
    "!pip list | grep langchain\n",
    "\n",
    "!pip list | grep qianfan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1413368a-0670-4af1-8c99-27312ef9e24c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting langchain==0.0.292\n",
      "  Obtaining dependency information for langchain==0.0.292 from https://files.pythonhosted.org/packages/86/dc/e2c7599b03455ea675107472b60e836f693ac8453e7c1119b61e6e60f574/langchain-0.0.292-py3-none-any.whl.metadata\n",
      "  Downloading langchain-0.0.292-py3-none-any.whl.metadata (14 kB)\n",
      "Requirement already satisfied: PyYAML>=5.3 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (6.0)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (2.0.18)\n",
      "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (3.8.4)\n",
      "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (4.0.2)\n",
      "Requirement already satisfied: dataclasses-json<0.6.0,>=0.5.7 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (0.5.9)\n",
      "Requirement already satisfied: langsmith<0.1.0,>=0.0.21 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (0.0.22)\n",
      "Requirement already satisfied: numexpr<3.0.0,>=2.8.4 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (2.8.4)\n",
      "Requirement already satisfied: numpy<2,>=1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (1.24.0)\n",
      "Requirement already satisfied: pydantic<3,>=1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (1.10.12)\n",
      "Requirement already satisfied: requests<3,>=2 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (2.31.0)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from langchain==0.0.292) (8.2.2)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp<4.0.0,>=3.8.3->langchain==0.0.292) (23.1.0)\n",
      "Requirement already satisfied: charset-normalizer<4.0,>=2.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp<4.0.0,>=3.8.3->langchain==0.0.292) (3.1.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp<4.0.0,>=3.8.3->langchain==0.0.292) (6.0.4)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp<4.0.0,>=3.8.3->langchain==0.0.292) (1.9.2)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp<4.0.0,>=3.8.3->langchain==0.0.292) (1.3.3)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp<4.0.0,>=3.8.3->langchain==0.0.292) (1.3.1)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.3.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from dataclasses-json<0.6.0,>=0.5.7->langchain==0.0.292) (3.19.0)\n",
      "Requirement already satisfied: marshmallow-enum<2.0.0,>=1.5.1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from dataclasses-json<0.6.0,>=0.5.7->langchain==0.0.292) (1.5.1)\n",
      "Requirement already satisfied: typing-inspect>=0.4.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from dataclasses-json<0.6.0,>=0.5.7->langchain==0.0.292) (0.9.0)\n",
      "Requirement already satisfied: typing-extensions>=4.2.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from pydantic<3,>=1->langchain==0.0.292) (4.7.1)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests<3,>=2->langchain==0.0.292) (3.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests<3,>=2->langchain==0.0.292) (1.26.16)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests<3,>=2->langchain==0.0.292) (2023.5.7)\n",
      "Requirement already satisfied: packaging>=17.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from marshmallow<4.0.0,>=3.3.0->dataclasses-json<0.6.0,>=0.5.7->langchain==0.0.292) (23.1)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from typing-inspect>=0.4.0->dataclasses-json<0.6.0,>=0.5.7->langchain==0.0.292) (1.0.0)\n",
      "Downloading langchain-0.0.292-py3-none-any.whl (1.7 MB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.7/1.7 MB\u001b[0m \u001b[31m1.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m0m\n",
      "\u001b[?25hInstalling collected packages: langchain\n",
      "  Attempting uninstall: langchain\n",
      "    Found existing installation: langchain 0.0.291\n",
      "    Uninstalling langchain-0.0.291:\n",
      "      Successfully uninstalled langchain-0.0.291\n",
      "Successfully installed langchain-0.0.292\n",
      "Requirement already satisfied: qianfan==0.0.3 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (0.0.3)\n",
      "Requirement already satisfied: erniebot>=0.1.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from qianfan==0.0.3) (0.2.0)\n",
      "Requirement already satisfied: aiohttp in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from erniebot>=0.1.0->qianfan==0.0.3) (3.8.4)\n",
      "Requirement already satisfied: bce-python-sdk in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from erniebot>=0.1.0->qianfan==0.0.3) (0.8.90)\n",
      "Requirement already satisfied: colorlog in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from erniebot>=0.1.0->qianfan==0.0.3) (6.7.0)\n",
      "Requirement already satisfied: requests>=2.20 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from erniebot>=0.1.0->qianfan==0.0.3) (2.31.0)\n",
      "Requirement already satisfied: typing-extensions in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from erniebot>=0.1.0->qianfan==0.0.3) (4.7.1)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests>=2.20->erniebot>=0.1.0->qianfan==0.0.3) (3.1.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests>=2.20->erniebot>=0.1.0->qianfan==0.0.3) (3.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests>=2.20->erniebot>=0.1.0->qianfan==0.0.3) (1.26.16)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from requests>=2.20->erniebot>=0.1.0->qianfan==0.0.3) (2023.5.7)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp->erniebot>=0.1.0->qianfan==0.0.3) (23.1.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp->erniebot>=0.1.0->qianfan==0.0.3) (6.0.4)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp->erniebot>=0.1.0->qianfan==0.0.3) (4.0.2)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp->erniebot>=0.1.0->qianfan==0.0.3) (1.9.2)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp->erniebot>=0.1.0->qianfan==0.0.3) (1.3.3)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from aiohttp->erniebot>=0.1.0->qianfan==0.0.3) (1.3.1)\n",
      "Requirement already satisfied: pycryptodome>=3.8.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from bce-python-sdk->erniebot>=0.1.0->qianfan==0.0.3) (3.18.0)\n",
      "Requirement already satisfied: future>=0.6.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from bce-python-sdk->erniebot>=0.1.0->qianfan==0.0.3) (0.18.3)\n",
      "Requirement already satisfied: six>=1.4.0 in /Users/xuwei/opt/anaconda3/envs/pytorch_m1/lib/python3.9/site-packages (from bce-python-sdk->erniebot>=0.1.0->qianfan==0.0.3) (1.16.0)\n"
     ]
    }
   ],
   "source": [
    "!pip install langchain==0.0.292\n",
    "!pip install qianfan==0.0.3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "981930ef-a0b4-46f9-b60b-a495117ea38e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ['QIANFAN_AK'] = \"your_api_key\"\n",
    "os.environ['QIANFAN_SK'] = \"your_secret_key\"\n",
    "\n",
    "# 此处为 Langsmith 相关功能开关。当且仅当你知道这是做什么用时，可删除注释并设置变量以使用 Langsmith 相关功能\n",
    "# os.environ['LANGCHAIN_TRACING_V2'] = \"true\"\n",
    "# os.environ['LANGCHAIN_ENDPOINT'] = \"https://api.smith.langchain.com\"\n",
    "# os.environ['LANGCHAIN_API_KEY'] = \"your_langchian_api_key\"\n",
    "# os.environ['LANGCHAIN_PROJECT'] = \"your_project_name\"\n",
    "\n",
    "is_chinese = True\n",
    "\n",
    "if is_chinese:\n",
    "    WEB_URL = \"https://zhuanlan.zhihu.com/p/85289282\"\n",
    "    CUSTOM_PROMPT_TEMPLATE = \"\"\"\n",
    "        使用下面的语料来回答本模板最末尾的问题。如果你不知道问题的答案，直接回答 \"我不知道\"，禁止随意编造答案。\n",
    "        为了保证答案尽可能简洁，你的回答必须不超过三句话。\n",
    "        请注意！在每次回答结束之后，你都必须接上 \"感谢你的提问\" 作为结束语\n",
    "        以下是一对问题和答案的样例：\n",
    "            请问：秦始皇的原名是什么\n",
    "            秦始皇原名嬴政。感谢你的提问。\n",
    "        \n",
    "        以下是语料：\n",
    "        \n",
    "        {context}\n",
    "        \n",
    "        请问：{question}\n",
    "    \"\"\"\n",
    "    QUESTION1 = \"明朝的开国皇帝是谁\"\n",
    "    QUESTION2 = \"朱元璋是什么时候建立的明朝\"\n",
    "else:\n",
    "    WEB_URL = \"https://lilianweng.github.io/posts/2023-06-23-agent/\"\n",
    "    CUSTOM_PROMPT_TEMPLATE = \"\"\"\n",
    "        Use the following pieces of context to answer the question at the end. \n",
    "        If you don't know the answer, just say that you don't know, don't try to make up an answer. \n",
    "        Use three sentences maximum and keep the answer as concise as possible. \n",
    "        Always say \"thanks for asking!\" at the end of the answer. \n",
    "        {context}\n",
    "        Question: {question}\n",
    "        Helpful Answer:\n",
    "    \"\"\"\n",
    "    QUESTION1 = \"How do agents use Task decomposition?\"\n",
    "    QUESTION2 = \"What are the various ways to implemet memory to support it?\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba5daed6",
   "metadata": {},
   "source": [
    "## Step 1. Load\n",
    "\n",
    "指定一个 `DocumentLoader` 来把你指定的非结构化数据加载成 `Documents`。一个 `Document` 是文字（即 `page_content`）和与之相关的元数据的结合体"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cf4d5c72",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.document_loaders import WebBaseLoader\n",
    "\n",
    "loader = WebBaseLoader(WEB_URL)\n",
    "data = loader.load()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a6196813",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Document(page_content='\\n中国古代史-明朝（1368~1644） - 知乎切换模式写文章登录/注册中国古代史-明朝（1368~1644）历史风云看历史，就看历史风云起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。“治河”和“变钞”导致红巾军起义爆发。郭子兴1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，聚众起义，攻占濠州。平民出身的朱元璋受汤和邀请投奔郭子兴，屡立战功，备受郭子兴器重和信任，并娶郭子兴养女马氏为妻。不久，朱元璋离开濠州，发展自己的势力。1355年，刘福通立韩林儿为帝，国号宋，年号龙凤，称小明王，以亳州为都城。郭子兴病故后朱元璋统率郭部，小明王任其为左副元帅。1356年，朱元璋占领集庆路，改名为应天府，并攻下周围战略要地，获取一块立足之地。朱元璋采纳朱升“高筑墙，广积粮，缓称王”的建议。1360年，鄱阳湖水战使陈友谅势力遭到巨大打击。1361年，小明王封朱元璋为吴国公。1363年，陈友谅败亡。1364年，朱元璋称王，史称“西吴”，与占平江府的东吴王张士诚相区别。1366年小明王、刘福通被廖永忠沉于瓜步江中溺死。1367年，攻下平江，张士诚自尽，后又灭浙江的方国珍。明朝的建立朱元璋1368年正月初四，朱元璋以应天府（南京）为京师，国号大明，年号洪武，朱元璋称帝。后进行北伐和西征，同年以“驱逐胡虏，恢复中华”的口号命徐达、常遇春等将北伐，攻占大都（即北京），元顺帝北逃，彻底结束蒙古在中原的统治，中国再次回归由汉族建立的王朝统治之下。之后朱元璋又相继消灭四川的明升和云南的梁王把匝剌瓦尔密、辽东的纳哈出。又八次派兵深入漠北，大破北元，天下至此初定。洪武之治朱元璋即位后采取轻徭薄赋，恢复社会生产，确立里甲制，配合赋役黄册户籍登记簿册和鱼鳞图册的施行，落实赋税劳役的征收及地方治安的维持。整顿吏治，惩治贪官污吏，促使社会经济得到恢复和发展，史称洪武之治。同时朱元璋多次派军北伐蒙古，取得多次胜利，最终在捕鱼儿海之役平定北元，消除外患。胡惟庸朱元璋平定天下后，大封功臣，也对功臣有所猜忌，恐其居功枉法，图谋不轨。而有的功臣也越过礼法，为非作歹。朱元璋借此兴胡惟庸案和蓝玉案，清理权贵和不法功勋。1380年朱元璋以擅权枉法之罪名杀胡惟庸，又杀御史大夫陈宁、御史中丞涂节等人。1390年有人告发李善长与胡惟庸关系密切，李善长因此被赐死，家属七十余人坐死，总计株连者达三万余人，史称胡惟庸案。此后，朱元璋又借大将军蓝玉张狂跋扈之名大加诛杀，连坐被族诛的有一万五千余人。加上空印案与郭桓案合称明初四大案。朱元璋通过打击功臣、设立锦衣卫加强特务监视等一系列手段来加强皇权。建文改制明惠宗1398年朱元璋驾崩，由于太子朱标早死，由皇太孙朱允炆即位，年号建文，即明惠宗。明惠宗为巩固皇权，与亲信大臣齐泰、黄子澄等密谋削藩。周王、代王、齐王、湘王等先后或被废为庶人，或被逼自杀。同时以边防为名调离燕王朱棣的精兵，欲铲除朱棣，朱棣在姚广孝的建议下以“清君侧，靖内难”的名义起兵，最后率军南下，攻占南京，史称靖难之役。后明惠宗在宫城大火中下落不明，朱棣即位，改元永乐。永乐盛世1405年，朱棣将北平改名北京，称行在，设立北平国子监等衙门。1416年，朱棣公布迁都的想法，隔年开始大规模营造北京，1420年完工，隔年迁都。明成祖永乐时期武功昌盛，天下大治，收复安南设交趾布政司，朱棣又亲自率兵五征漠北攻打北元分裂后的鞑靼与瓦剌。朱棣册封瓦剌三王，使与鞑靼对立，见瓦剌中兴之势，又助鞑靼讨伐瓦剌，不使任何一方独大。同时授予兀良哈蒙古的朵颜、泰宁和福余三个卫所自治权。朱棣还于1406年和1422年对兀良哈蒙古进行镇压，以维持这一地区的稳定。朱棣安抚东北女真各部，在归附的建州女真、海西女真设置卫所，并派亦失哈安抚黑龙江下游的野人女真。1407年亦失哈在混同江庙街的对岸塔林设奴儿干都司，扩大明朝东疆，亦失哈并于1413年视察库页岛，宣示明朝对此地的主权。郑和朱棣实行积极的外交策略，自1405年开始派郑和下西洋，与各国进行政治经济来往，增长财政收入的同时将朝贡制度推向巅峰。其舰队规模空前庞大，最远到达东非索马里地区，扩大明朝对南洋、西洋各国的影响力。文治方面，朱棣令编修百科全书《永乐大典》，解缙率三千文人在三年时间内即告完成。《永乐大典》有22877卷，又凡例、目录60卷，11095册，引书达七八千种，字数约有三亿七千多万，且无删节。朱棣对异议者强力镇压，诸如黄子澄、齐泰等建文旧臣等都被杀。其中以方孝孺的诛十族和景清的“瓜蔓抄”最为惨烈。还恢复了明太祖时期后来被废除的锦衣卫，另外他还设置了另外一个特务组织——东厂。厂卫制度确立。仁宣之治朱棣驾崩后，其长子朱高炽即位，即明仁宗，年号洪熙。仁宗年龄已经偏高，即位仅一年就驾崩。其统治偏向保守固本，注重休养生息。任用“三杨”（杨士奇、杨荣、杨溥）等贤臣辅佐朝政，停止郑和下西洋和对外战争以积蓄民力，鼓励生产，宽行省狱，力行节俭。明仁宗仁宗驾崩后长子朱瞻基即位，是为明宣宗，年号宣德。宣宗实行德政治国，并且先后派遣郑和、王景弘下西洋，使国力达到极盛，史称“仁宣之治”。宣宗同样擅长书画，有画作传世。但其执政期间并非毫无弊端，由于宣宗喜好养蟋蟀，许多官吏因此竞相拍马，被称为“促织天子”。同时宣宗设立内书堂教宦官读书，为明英宗时期的太监乱政埋下隐患。明宣宗土木之变与北京保卫战1435年，九岁的朱祁镇继位，即明英宗，年号正统。此时太监王振开始干涉朝政，1442年遏制王振权势的张太皇太后去世后王振大肆揽权。元老重臣“三杨”死后，王振更专横跋扈，将明太祖留下的禁止宦官干政的敕命铁牌撤下，举朝称其为“翁父”，英宗对他信任有加。王振擅权七年，家产计有金银六十余库。明英宗1435年蒙古西部的瓦剌逐渐强盛常寇边。1449年瓦剌首领也先率军南下伐明。王振怂使英宗集结二十万京营御驾亲征。大军离燕京后，兵士乏粮劳顿，八月初大军才至大同，王振得报前线各路溃败，惧不敢战，又令返回。回师至土木堡，被瓦剌军追上，士兵死伤过半，随从大臣有五十余人阵亡。英宗突围不成被俘，王振为将军樊忠所怒杀，史称土木之变，是明朝由盛转衰的转折点。兵部侍郎于谦拥戴英宗弟弟朱祁钰即位，即明代宗，年号景泰。于谦升任兵部尚书，决定坚守北京，整顿边防积极备战，随后南直隶、河南、山东等地勤王部队陆续赶到。同年十月，瓦剌军直逼北京城下，也先安置明英宗于德胜门外土关。于谦率领各路明军奋勇抗击，屡次大破瓦剌军，也先率军撤退。明朝取得北京保卫战的胜利，于谦力排众议，加紧巩固国防，拒绝求和，并于次年击退瓦剌多次侵犯。明代宗夺门之变与石曹之乱1450年也先释放英宗。然而代宗因为皇权问题不愿遣使迎驾，后又把英宗困于南宫（重华宫）软禁，并废皇太子朱见深，立自己的儿子朱见济为太子。不久见济病死，代宗迟迟不肯再立朱见深为太子，俨然有夺正之态，英宗、代宗因而严重对立。1457年石亨、徐有贞、曹吉祥等人联盟，欲拥戴英宗复辟。趁着明代宗重病之际发动政变。徐有贞率军攻入紫禁城，石亨等人占领东华门，立明英宗于奉天殿，改元天顺。他们贬明代宗为郕王，并且逮处死于谦及大学士王文，史称夺门之变。明英宗复辟后，略有新政，废除自明太祖恢复的殉葬。之后因内部政变流放徐有贞，因曹石之乱诛杀石亨、曹吉祥等人，任命李贤等贤臣治国。明宪宗1464年英宗驾崩，朱见深即位，即明宪宗，年号成化。宪宗为于谦平反，恢复代宗帝号，时人多称快，又能体谅民情，励精图治，宛若明君之资。琉球、哈密、暹罗、土鲁番、撒马儿罕等国纷纷入贡。但其本人口吃内向，因此很少廷见大臣，宠爱亦妻亦母的万贵妃，宠信宦官汪直、梁芳等人，晚年好方术，以至奸佞当权，西厂横恣，朝纲败坏，民不聊生。宪宗直接颁诏封官，是为传奉官，造成舞弊成风，直到孝宗才全被裁撤。弘治中兴明孝宗1487年明宪宗驾崩，其子朱祐樘继位，即明孝宗，年号弘治。孝宗在位期间“更新庶政，言路大开”，使自英宗以来的陋习得以去除，被誉为“中兴令主”。孝宗先是将成化年间的一批奸佞冗官尽数罢免，逮捕治罪，并选贤任能以委重任。孝宗勤于政事，每日两次视朝。明孝宗对宦官严加节制，锦衣卫与东厂也谨慎行事，法治宽刑。孝宗力行节俭，不大兴土木，减免税赋。明史称孝宗为“恭俭有制，勤政爱民”，在其治理下，弘治一朝期间政治清明，百姓安居乐业，史称弘治中兴。明武宗1505年孝宗去世，其子朱厚照即位，为明武宗，年号正德。武宗即位后清代野史常说他极好逸乐，导致正德年间战事频生，外有鞑靼达延汗进犯、内有叛乱和民变等重大事件。1520年武宗借出征江西宁王叛乱为由而南下游玩，以大将军朱寿为名前往南京，亲自俘虏已被王守仁击败的宁王。班师回京途中，于南直隶清江浦泛舟取乐时落水染病，1521年于豹房驾崩。因死后无子使孝宗一脉绝嗣。嘉靖中兴明世宗明武宗驾崩后，明孝宗之侄、兴献王之子朱厚熜入嗣大统，是为世宗。登基前后，因时任内阁首辅杨廷和、礼部尚书毛澄等权臣引宋濮安事强令世宗皇帝尊亲生父母为皇叔父母，导致大礼议之争。最终世宗扫灭宦官和权臣势力，总揽朝纲。1534年后世宗即不视朝，但仍悉知帝国事务，事无巨细仍出于世宗决断。世宗信奉道教，信用方士，在宫中日夜祈祷。先是将道士邵元节入京，封为真人及礼部尚书。邵死后又大宠方士陶仲文。1542年十月，乾清宫发生杨金英、邢翠莲等宫女十余人与宁嫔王氏趁世宗熟睡之际企图将其勒死，史称壬寅宫变。此事后，直至世宗驾崩前一晚，世宗迁离大内移居西内。戚继光嘉靖一朝，国家外患不断。北方鞑靼趁明朝衰弱而入据河套。1550年鞑靼首领俺答进犯大同，宣大总兵仇鸾重金收买俺答，让其转向其他目标。结果俺答转而直攻北京，在北京城郊大肆抢掠后西去，明朝军队在追击过程中战败，此为庚戌之变。东南沿海由日本浪人与中国海盗组成的倭寇与沿海居民合作走私，先并且后袭扰山东、浙江、福建与广东等地区。戚继光与俞大猷平定浙闽粤等地的倭寇，为隆庆开关奠定基础。另葡萄牙人于1557年移民澳门，但及至明亡，葡萄牙人及澳门始终为广东布政司香山县管辖。1566年明世宗驾崩，皇太子朱载垕即位，即明穆宗，年号隆庆，翌年为隆庆元年。明穆宗万历革新明穆宗即位后启用在藩邸的老师高拱、张居正。隆庆初年，位处执政之首的世宗旧臣徐阶策动朝官弹劾高拱，高拱辞官回乡。高拱亦不甘示弱，一年后策动朝官弹劾徐阶。徐阶也被迫正式退休。朝廷的实际政务渐渐落到了张居正的手上。隆庆末年，高拱回朝出任内阁首辅。隆庆朝名臣名将荟萃，陆上与蒙古达成和议，史称俺答封贡；海上开放民间贸易，史称隆庆开关；因为这两项措施，明朝又重现中兴气象，史称隆庆新政。1572年，明穆宗因中风突然驾崩，年仅九岁的皇太子朱翊钧继位，改元万历。由于年幼由太后摄政，重臣高拱因与太后信任的宦官冯保对抗而被罢官，张居正则得到冯保的鼎力支持。张居正辅政十年，推行改革，在内政方面，推行考成法，裁撤政府机构中的冗官冗员，整顿邮传和铨政。经济上，清丈全国土地，抑制豪强地主，改革赋役制度，推行一条鞭法，减轻农民负担。军事上，加强武备整顿，平定西南骚乱，重用抗倭名将戚继光总督蓟、昌、保三镇练兵镇守长城，使边境安然。张居正还启用潘季驯治理黄河，变水患为水利。同时张居正严惩贪官污吏，裁汰冗员。张居正整顿朝正，改革体制，史称万历中兴。明神宗1577年秋，张居正父亲去世，按常理他需要丁忧，但张居正以为改革事业未竟，不愿丁忧。他的政敌借此大做文章，史称夺情之争。最后在明神宗和两太后的力挺下张居正被夺情起复，使得其改革并未被中断。但是，这成为了他的政敌之借口。同时张居正利用职权让亲子通过科举进入翰林院。张居正死后被反对改革的政敌清算。张府家属被囚禁于内，饿死十余口，生前官爵也被剥夺。东林党争与国本之争张居正死后初期，明神宗尚能保持对朝政的兴趣，在位期间有东林党争、国本之争等重大事件，对外有朝鲜之役与萨尔浒之战。万历一朝成为明朝由盛转衰的转折期。张居正国本之争主要围绕着皇长子朱常洛与福王朱常洵。明神宗迟迟不立太子，令群臣忧心如焚。直到1601年，朱常洛才被封为太子，朱常洵被封为福王。但是福王迟迟不离京就任藩王。直到梃击案发生，舆论对郑贵妃不利后，福王才离京就藩。明神宗于国本之争对大臣极度不满，自1587年后，就开始连续不上朝作为报复，仅处理一些重要事件。自1588年后，早朝也经常看不到他，整日在深宫中不理政事。东林党源于顾宪成组办的东林书院。东林党争起因是内阁缺人，顾宪成极力主张颇有政绩的淮扬巡抚李三才入阁，结果被反对李三才入阁的势力抹黑漫骂，东林党因此兴起，朝中其它各党便集中火力攻击东林党。阉党专权后，东林党更受到严重打击，直到崇祯年间东林党才重新被启用。由于明神宗不理朝政，缺官现象非常严重。1602年，南北两京共缺尚书三名，侍郎十名；各地缺巡抚三名，布政使、按察使等六十六名，知府二十五名。明神宗委顿于上，百官党争于下，明廷完全陷入空转之中。官僚队伍中党派林立，互相倾轧，如东林党、宣党、昆党、齐党、浙党等名目众多，但其所议议题却不是如何改良朝政，只是人事布局而已。在东北，由于深受明神宗信任的辽东总兵李成梁后期腐化堕落，大肆谎报军情，骗取军功封赏，军事打击目标上偏袒努尔哈赤势力，致使明末边患严重，并最终导致清朝入主中国。因此《明史》言：“论者谓：明之亡，实亡于神宗。”在军事方面，万历朝以万历三大征最为功勋卓著，三战皆胜以巩固明朝边疆、守护朝鲜王朝，但也消耗了明朝国库存银。1617年，努尔哈赤以“七大恨”反明，两年后在萨尔浒之战中大败明军，明朝对后金从此转为战略防御。明光宗1620年，明神宗驾崩。其长子朱常洛登基，为明光宗，明光宗仅在位一个月，八月二十九日，又因服用李可灼的红丸，九月一日五更时猝死。明熹宗继位，改元天启。阉党专权明熹宗早期大量启用东林党人，加剧东林党争，明熹宗因此对朝政失去耐心，魏忠贤趁机干预政治，拉拢齐楚浙党，号为阉党。1624年后，阉党把握朝政，魏忠贤擅权跋扈，爪牙遍布全国，并大肆打击东林党，借“梃击案、红丸案、移宫案”为由，唆使其党羽伪造《东林党点将录》上报朝廷，1625年明熹宗下诏，烧毁全国书院。大量东林党人入狱，甚至处死，天启年间的朝政混乱导致内忧外患加剧。魏忠贤1626年北京西南隅的工部王恭厂火药库发生王恭厂大爆炸，造成2万多人死伤。当时东北方的后金逐步占领辽东地区。1626年，努尔哈赤率军攻打宁远，明军在袁崇焕的指挥下凭借坚城固守抗敌，最终击败后金军，并击伤努尔哈赤，史称“宁远大捷”。不久后，努尔哈赤死去，其子皇太极即位。袁崇焕崇祯治乱1627年明熹宗不慎落水病重，不久因霍维华之药而驾崩，信王朱由检继位，即明思宗，年号崇祯。崇祯即位后，锐意铲除阉党改革朝政。他下令停建生祠，逼奉圣夫人客氏移居宫外，最后押到浣衣局处死。下令魏忠贤去凤阳守陵，魏忠贤于途中与党羽李朝钦一起自缢，明思宗将其首级悬于河间老家，阉党其它分子也被贬黜或处死。然而崇祯用人多疑、刚愎自用、举棋不定导致局势愈加糜烂。明思宗1629年皇太极改采绕道长城以入侵北京，袁崇焕紧急回军与皇太极对峙于北京广渠门。经六部九卿会审，最后杀袁崇焕，史称己巳之变。其后皇太极多番远征蒙古，终于在六年后彻底击败林丹汗，次年在盛京称帝，改国号为大清，并五次经长城入侵明朝北直隶、山东等地区，史称清兵入塞。当时北直隶连年灾荒疫疾，民不聊生。辽西局势亦日益恶化，清军多次与明军作战，最后于1640年占领锦州等地，明军主力洪承畴等人投降，明朝势力退缩至山海关。明中期之后时常发生农民起事，崇祯时期朝政混乱与官员贪污昏庸；与后金的战争带来大量辽饷的需求以及清兵的掠夺；以及因为小冰期气候变冷，农业减产带来全国性饥荒，这些都加重明朝百姓的负担。1627年，陕西澄城饥民暴动，拉开明末民变的序幕，随后王自用、高迎祥、李自成、张献忠等农民起事，最后发展成雄踞陕西、河南的李自成与先后占领湖广、四川的张献忠。1644年李自成建国大顺，三月，李自成率军北伐攻陷大同、宣府、居庸关，最后攻克北京。崇祯在煤山自缢，明朝作为统一国家的历史结束。南明时期北京沦陷后，史可法等人在南京拥立福王朱由崧，建立弘光政权，即弘光帝，弘光帝死后，鲁王朱以海于浙江绍兴监国；而唐王朱聿键在郑芝龙等人的拥立下，于福建福州称帝，即隆武帝。而两个南明政权为争夺正统地位互相攻伐。1651年在舟山群岛沦陷后，鲁王朱以海在张名振、张煌言陪同下，赴厦门依靠郑成功，不久病死在金门。隆武帝屡议出师北伐，因得不到郑芝龙的支持而无疾而终。1646年，清军攻占浙江与福建，鲁王逃亡海外，隆武帝于汀州逃往江西时被俘，绝食殉国，郑芝龙向清军投降，然而由于其子郑成功反清而被清廷囚禁。朱聿键之弟朱聿鐭在广州受苏观生及顾元镜拥立，即绍武帝，于同年年底被清将李成栋攻灭。同时间桂王朱由榔于广东肇庆称帝，即永历帝。1646年永历政权获得瞿式耜、张献忠余部李定国、孙可望等势力以及福建郑成功势力的支持下展开反攻。同时各地降清的原明军将领先后反正，如1648年江西金声桓、广东李成栋、广西耿献忠与杨有光率部反正，一时之间南明收服华南各省。然而于同年，清将尚可喜率军再度入侵，先后占领湖南、广东等地。两年后，李定国、孙可望与郑成功发动第二次反攻，其中郑成功一度包围南京，但最后因内部孙可望叛变及反清势力鞭长莫及与之间的貌合神离最终导致节节败退。1661年清军三路攻入云南，永历帝流亡缅甸首都曼德勒，被缅甸王莽达收留。后吴三桂攻入缅甸，莽达之弟莽白乘机发动政变，杀死其兄后于8月12日发动咒水之难，杀尽朱由榔侍从近卫，朱由榔最后被吴三桂所杀，南明亡。李自成余部在湖南抗清失败后，转移到川、鄂山区进行活动，在夔州府以东地区继续抗清，称为夔东十三家军。1662年清军开始攻打，到1664年首领李来亨被杀而亡。明郑时期郑成功在南京之战失败后退回金厦，于1661年率军攻占荷兰占据的台湾，定都东宁。其子郑经曾参与三藩之乱，率军参与反攻失利。1683年，康熙帝命施琅进攻明郑。施琅大败刘国轩攻克澎湖，给台湾造成战略威胁，最终郑克塽剃发降清，明朝宁靖王朱术桂携五妃自杀殉国，最后一股抗清势力覆灭。发布于 2019-10-05 20:39\\u200b赞同\\u200b\\u200b添加评论\\u200b分享\\u200b喜欢\\u200b收藏\\u200b申请转载\\u200b', metadata={'source': 'https://zhuanlan.zhihu.com/p/85289282', 'title': '中国古代史-明朝（1368~1644） - 知乎', 'description': '起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。 “治河”和“变钞”导致红巾军起义爆发。 1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，…', 'language': 'zh'})]\n"
     ]
    }
   ],
   "source": [
    "print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd2cc9a7",
   "metadata": {},
   "source": [
    "## Step 2. Split\n",
    "\n",
    "接下来把 `Document` 切分成块，为后续的 embedding 和存入向量数据库做准备。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4b11c01d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "\n",
    "text_splitter = RecursiveCharacterTextSplitter(chunk_size = 384, chunk_overlap = 0, separators=[\"\\n\\n\", \"\\n\", \" \", \"\", \"。\", \"，\"])\n",
    "all_splits = text_splitter.split_documents(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a33bd4d",
   "metadata": {},
   "source": [
    "## Step 3. Store\n",
    "\n",
    "为了能够查询文档的片段，我们首先需要把它们存储起来，一种比较常见的做法是对文档的内容做 embedding，然后再将 embedding 的向量连同文档一起存入向量数据库中，此处 embedding 用于索引文档。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e9c302c8",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [09-18 22:05:21] logging.py:55 [t:8594340480]: trying to refresh access_token\n",
      "[INFO] [09-18 22:05:21] logging.py:55 [t:8594340480]: sucessfully refresh access_token\n",
      "[INFO] [09-18 22:05:21] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n",
      "[INFO] [09-18 22:05:22] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n"
     ]
    }
   ],
   "source": [
    "from langchain.embeddings import QianfanEmbeddingsEndpoint\n",
    "from langchain.vectorstores import Chroma\n",
    "\n",
    "vectorstore = Chroma.from_documents(documents=all_splits, embedding=QianfanEmbeddingsEndpoint())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc6f22b0",
   "metadata": {},
   "source": [
    "除了非结构化的文档以外，Langchain 还可以从多种数据源获取数据并将它们存储起来。\n",
    "\n",
    "![lc.png](img/qa_data_load.png)\n",
    "\n",
    "## Step 4. Retrieve\n",
    "\n",
    "我们可以使用 [相似度搜索](https://www.pinecone.io/learn/what-is-similarity-search/) 来从切分的文档内获取数据，获取到的数据会作为最终提交给 LLM 的 prompt 的一部分。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e2c26b7d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [09-18 22:06:11] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "prompt问题：明朝的开国皇帝是谁\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[('中国古代史-明朝（1368~1644） -', 0.46182550051839333),\n",
       " ('知乎切换模式写文章登录/注册中国古代史-明朝（1368~1644）历史风云看历史，就看历史风云起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。“治河”和“变钞”导致红巾军起义爆发。郭子兴1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，聚众起义，攻占濠州。平民出身的朱元璋受汤和邀请投奔郭子兴，屡立战功，备受郭子兴器重和信任，并娶郭子兴养女马氏为妻。不久，朱元璋离开濠州，发展自己的势力。1355年，刘福通立韩林儿为帝，国号宋，年号龙凤，称小明王，以亳州为都城。郭子兴病故后朱元璋统率郭部，小明王任其为左副元帅。1356年，朱元璋占领集庆路，改名为应天府，并攻下周围战略要地，获取一块立足之地。朱元璋采纳朱升“高筑墙，广积粮，缓称王”的建议。1360年，鄱阳湖水战使陈友谅势力遭到巨大打击。1361',\n",
       "  0.3850624338011377),\n",
       " ('年，小明王封朱元璋为吴国公。1363年，陈友谅败亡。1364年，朱元璋称王，史称“西吴”，与占平江府的东吴王张士诚相区别。1366年小明王、刘福通被廖永忠沉于瓜步江中溺死。1367年，攻下平江，张士诚自尽，后又灭浙江的方国珍。明朝的建立朱元璋1368年正月初四，朱元璋以应天府（南京）为京师，国号大明，年号洪武，朱元璋称帝。后进行北伐和西征，同年以“驱逐胡虏，恢复中华”的口号命徐达、常遇春等将北伐，攻占大都（即北京），元顺帝北逃，彻底结束蒙古在中原的统治，中国再次回归由汉族建立的王朝统治之下。之后朱元璋又相继消灭四川的明升和云南的梁王把匝剌瓦尔密、辽东的纳哈出。又八次派兵深入漠北，大破北元，天下至此初定。洪武之治朱元璋即位后采取轻徭薄赋，恢复社会生产，确立里甲制，配合赋役黄册户籍登记簿册和鱼鳞图册的施行，落实赋税劳役的征收及地方治安的维持。整顿吏治，惩治贪官污',\n",
       "  0.3646482284032496),\n",
       " ('军情，骗取军功封赏，军事打击目标上偏袒努尔哈赤势力，致使明末边患严重，并最终导致清朝入主中国。因此《明史》言：“论者谓：明之亡，实亡于神宗。”在军事方面，万历朝以万历三大征最为功勋卓著，三战皆胜以巩固明朝边疆、守护朝鲜王朝，但也消耗了明朝国库存银。1617年，努尔哈赤以“七大恨”反明，两年后在萨尔浒之战中大败明军，明朝对后金从此转为战略防御。明光宗1620年，明神宗驾崩。其长子朱常洛登基，为明光宗，明光宗仅在位一个月，八月二十九日，又因服用李可灼的红丸，九月一日五更时猝死。明熹宗继位，改元天启。阉党专权明熹宗早期大量启用东林党人，加剧东林党争，明熹宗因此对朝政失去耐心，魏忠贤趁机干预政治，拉拢齐楚浙党，号为阉党。1624年后，阉党把握朝政，魏忠贤擅权跋扈，爪牙遍布全国，并大肆打击东林党，借“梃击案、红丸案、移宫案”为由，唆使其党羽伪造《东林党点将录》上报朝廷',\n",
       "  0.30970618674032735)]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 基于prompt问题查找相似文档\n",
    "print(\"prompt问题：\"+QUESTION1)\n",
    "docs = vectorstore.similarity_search_with_relevance_scores(QUESTION1)\n",
    "[(document.page_content, score) for document, score in docs]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "415d6824",
   "metadata": {},
   "source": [
    "## Step 5. Generate\n",
    "\n",
    "接下来我们就可以使用我们的大模型（例如文心一言）和 Langchain 的 RetrievalQA 链，来针对这篇文档进行提问并获取我们想要的回答了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "99fa1aec",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [09-18 22:07:20] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n",
      "[INFO] [09-18 22:07:21] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'query': '明朝的开国皇帝是谁', 'result': '明朝的开国皇帝是朱元璋。感谢你的提问。'}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "from langchain.chat_models import QianfanChatEndpoint\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "QA_CHAIN_PROMPT = PromptTemplate.from_template(CUSTOM_PROMPT_TEMPLATE)\n",
    "\n",
    "llm = QianfanChatEndpoint(streaming=True)\n",
    "retriever=vectorstore.as_retriever(search_type=\"similarity_score_threshold\", search_kwargs={'score_threshold': 0.0})\n",
    "                                   \n",
    "qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={\"prompt\": QA_CHAIN_PROMPT})\n",
    "qa_chain({\"query\": QUESTION1})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7d52c84",
   "metadata": {},
   "source": [
    "注意，此处不光可以传入 `ChatModel` ，也可以传入一个 `LLM` 对象到 `RetrievalQA` 中。并且通过代码我们可以看到，用户可以通过传入额外的命名参数字典来自定义我们所需使用的 prompt 模板"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff40e8db",
   "metadata": {},
   "source": [
    "#### 返回源文档\n",
    "\n",
    "用于 QA 的知识文档也可以通过指定 `return_source_documents=True` 被包含在返回的字典里"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "60004293",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [09-18 22:07:53] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n",
      "[INFO] [09-18 22:07:53] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[Document(page_content='中国古代史-明朝（1368~1644） -', metadata={'description': '起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。 “治河”和“变钞”导致红巾军起义爆发。 1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，…', 'language': 'zh', 'source': 'https://zhuanlan.zhihu.com/p/85289282', 'title': '中国古代史-明朝（1368~1644） - 知乎'}),\n",
       " Document(page_content='知乎切换模式写文章登录/注册中国古代史-明朝（1368~1644）历史风云看历史，就看历史风云起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。“治河”和“变钞”导致红巾军起义爆发。郭子兴1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，聚众起义，攻占濠州。平民出身的朱元璋受汤和邀请投奔郭子兴，屡立战功，备受郭子兴器重和信任，并娶郭子兴养女马氏为妻。不久，朱元璋离开濠州，发展自己的势力。1355年，刘福通立韩林儿为帝，国号宋，年号龙凤，称小明王，以亳州为都城。郭子兴病故后朱元璋统率郭部，小明王任其为左副元帅。1356年，朱元璋占领集庆路，改名为应天府，并攻下周围战略要地，获取一块立足之地。朱元璋采纳朱升“高筑墙，广积粮，缓称王”的建议。1360年，鄱阳湖水战使陈友谅势力遭到巨大打击。1361', metadata={'description': '起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。 “治河”和“变钞”导致红巾军起义爆发。 1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，…', 'language': 'zh', 'source': 'https://zhuanlan.zhihu.com/p/85289282', 'title': '中国古代史-明朝（1368~1644） - 知乎'}),\n",
       " Document(page_content='年，小明王封朱元璋为吴国公。1363年，陈友谅败亡。1364年，朱元璋称王，史称“西吴”，与占平江府的东吴王张士诚相区别。1366年小明王、刘福通被廖永忠沉于瓜步江中溺死。1367年，攻下平江，张士诚自尽，后又灭浙江的方国珍。明朝的建立朱元璋1368年正月初四，朱元璋以应天府（南京）为京师，国号大明，年号洪武，朱元璋称帝。后进行北伐和西征，同年以“驱逐胡虏，恢复中华”的口号命徐达、常遇春等将北伐，攻占大都（即北京），元顺帝北逃，彻底结束蒙古在中原的统治，中国再次回归由汉族建立的王朝统治之下。之后朱元璋又相继消灭四川的明升和云南的梁王把匝剌瓦尔密、辽东的纳哈出。又八次派兵深入漠北，大破北元，天下至此初定。洪武之治朱元璋即位后采取轻徭薄赋，恢复社会生产，确立里甲制，配合赋役黄册户籍登记簿册和鱼鳞图册的施行，落实赋税劳役的征收及地方治安的维持。整顿吏治，惩治贪官污', metadata={'description': '起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。 “治河”和“变钞”导致红巾军起义爆发。 1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，…', 'language': 'zh', 'source': 'https://zhuanlan.zhihu.com/p/85289282', 'title': '中国古代史-明朝（1368~1644） - 知乎'}),\n",
       " Document(page_content='军情，骗取军功封赏，军事打击目标上偏袒努尔哈赤势力，致使明末边患严重，并最终导致清朝入主中国。因此《明史》言：“论者谓：明之亡，实亡于神宗。”在军事方面，万历朝以万历三大征最为功勋卓著，三战皆胜以巩固明朝边疆、守护朝鲜王朝，但也消耗了明朝国库存银。1617年，努尔哈赤以“七大恨”反明，两年后在萨尔浒之战中大败明军，明朝对后金从此转为战略防御。明光宗1620年，明神宗驾崩。其长子朱常洛登基，为明光宗，明光宗仅在位一个月，八月二十九日，又因服用李可灼的红丸，九月一日五更时猝死。明熹宗继位，改元天启。阉党专权明熹宗早期大量启用东林党人，加剧东林党争，明熹宗因此对朝政失去耐心，魏忠贤趁机干预政治，拉拢齐楚浙党，号为阉党。1624年后，阉党把握朝政，魏忠贤擅权跋扈，爪牙遍布全国，并大肆打击东林党，借“梃击案、红丸案、移宫案”为由，唆使其党羽伪造《东林党点将录》上报朝廷', metadata={'description': '起源元朝末年蒙古统治者残暴，人民受到空前压迫。1351年，元廷征调农民和兵士十几万人治理黄河水患。 “治河”和“变钞”导致红巾军起义爆发。 1351年5月，韩山童、刘福通领导红巾军起义爆发。次年，郭子兴响应，…', 'language': 'zh', 'source': 'https://zhuanlan.zhihu.com/p/85289282', 'title': '中国古代史-明朝（1368~1644） - 知乎'})]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "\n",
    "qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever, chain_type_kwargs={\"prompt\": QA_CHAIN_PROMPT}, return_source_documents=True)\n",
    "result = qa_chain({\"query\": QUESTION1})\n",
    "len(result['source_documents'])\n",
    "result['source_documents']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4380e478-e8ae-404b-9577-6b15475a6562",
   "metadata": {},
   "source": [
    "## Step 6. Chat\n",
    "\n",
    "我们还可以加入 `Memory` 模块并替换使用 `ConversationalRetrievalChain` 来实现记忆化的对话式查询。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "6f56838d-29a5-405f-a6ba-7b687ee56268",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [09-18 22:09:18] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n",
      "[INFO] [09-18 22:09:18] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n",
      "[INFO] [09-18 22:09:18] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n",
      "[INFO] [09-18 22:09:19] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'question': '明朝的开国皇帝是谁',\n",
       " 'chat_history': [SystemMessage(content='', additional_kwargs={})],\n",
       " 'answer': '明朝的开国皇帝是朱元璋。'}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.memory import ConversationSummaryMemory\n",
    "from langchain.chains import ConversationalRetrievalChain\n",
    "\n",
    "memory = ConversationSummaryMemory(llm=llm,memory_key=\"chat_history\",return_messages=True)\n",
    "qa = ConversationalRetrievalChain.from_llm(llm, retriever=retriever, memory=memory, combine_docs_chain_kwargs={\"prompt\": QA_CHAIN_PROMPT})\n",
    "qa(QUESTION1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "a0d9d803-c183-49c8-97b0-1d5fed7ac52a",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] [09-18 22:09:27] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n",
      "[INFO] [09-18 22:09:28] logging.py:55 [t:8594340480]: requesting llm api endpoint: /embeddings/embedding-v1\n",
      "[INFO] [09-18 22:09:28] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n",
      "[INFO] [09-18 22:09:30] logging.py:55 [t:8594340480]: requesting llm api endpoint: /chat/eb-instant\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'question': '朱元璋是什么时候建立的明朝',\n",
       " 'chat_history': [SystemMessage(content=\"Human asks about the Ming Dynasty's founding emperor. AI answers that the founding emperor of the Ming Dynasty was Zhu Yuanzhang.\", additional_kwargs={})],\n",
       " 'answer': '朱元璋建立明朝的具体时间是1368年。'}"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qa(QUESTION2)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
